/*
 * Job.java
 *
 * Copyright 2012 the original author or authors(ninglong).
 *
 * Licensed under the org.geek.domain, Version 1.0 (the "License");
 *
 */
package org.geek.core.mybatis.domain;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Date;

import org.geek.app.job.service.impl.CronExpression;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.util.ClassUtils;

/**
 * <p></p>
 * @author ninglong bhd2973@qq.com
 * @version V1.0
 */
public class Job implements Serializable,Runnable {

	private static final long serialVersionUID = 1130821392199198651L;
	
	private static final String DEFAULT_GROUP_NAME = "DEFAULT";
	
	private static final int JOB_RUN_ON_START = 1;
	
	public static int JOB_RAM = 0;
	
	public static int JOB_DB = 1;
	
	private int jobId;
	
	private String jobGroupName;
	
	private String jobIdInGroup;
	
	private long jobExceuteTime;
	
	private String serviceName;
	
	private String methodName;
	
	private Object [] jobParams;
	
	private String jobPara = null;
	
	private int jobType = JOB_DB;
	
	private int runOnStart = 0;
	
	private String dispath;
	
	private String errorDesc;
	
	private String repeatRunRule;
	
	private transient CronExpression cronExpression;
	private transient boolean isJobRun = false;
	private transient boolean errorJob;
	
	private transient Date lastRunDate;
	
	private String key = null;
	private transient int retryCount;
	
	public boolean isErrorJob(){
		return errorJob;
	}

	public void setErrorJob(boolean errorJob) {
		this.errorJob = errorJob;
	}

	public CronExpression getCronExpression() {
		if(cronExpression == null){
			if(repeatRunRule != null && !"".equals(repeatRunRule)){
				try{
					cronExpression = new CronExpression(repeatRunRule);
				}catch(Exception e){
					e.printStackTrace();
					repeatRunRule = null;
				}
			}
		}
		return cronExpression;
	}
	public long getNextTime(){
		long now = System.currentTimeMillis();
		if(runOnStart >=JOB_RUN_ON_START){
			int nextTime = runOnStart;
			runOnStart = 0;
			return nextTime;
		}
		CronExpression exp =  getCronExpression();
		if(exp != null){
			if(lastRunDate == null){
				lastRunDate = new Date();
			}else{
				if(lastRunDate.getTime() < now){
					lastRunDate = new Date();
				}
			}
			Date date = exp.getNextValidTimeAfter(lastRunDate);
			if(date != null){
				long nextTime = date.getTime() - now;
				lastRunDate = date;
				return nextTime;
			}
		}
		return -1;
	}

	public int getJobId() {
		return jobId;
	}

	public void setJobId(int jobId) {
		this.jobId = jobId;
	}

	public String getJobGroupName() {
		if(jobGroupName == null){
			jobGroupName = DEFAULT_GROUP_NAME;
		}
		return jobGroupName;
	}

	public void setJobGroupName(String jobGroupName) {
		this.jobGroupName = jobGroupName;
		this.key = null;
	}

	public String getJobIdInGroup() {
		if(jobIdInGroup == null){
			jobIdInGroup = String.valueOf(jobId);
		}
		return jobIdInGroup;
	}

	public void setJobIdInGroup(String jobIdInGroup) {
		this.jobIdInGroup = jobIdInGroup;
		this.key = null;
	}

	public long getJobExceuteTime() {
		return jobExceuteTime;
	}

	public void setJobExceuteTime(long jobExceuteTime) {
		this.jobExceuteTime = jobExceuteTime;
	}

	public String getServiceName() {
		return serviceName;
	}

	public void setServiceName(String serviceName) {
		this.serviceName = serviceName;
	}

	public String getMethodName() {
		return methodName;
	}

	public void setMethodName(String methodName) {
		this.methodName = methodName;
	}

	public Object[] getJobParams() {
		return jobParams;
	}

	public void setJobParams(Object[] jobParams) {
		for(Object obj : jobParams){
			jobPara = jobPara+obj+",";
		}
		this.jobParams = jobParams;
	}

	public String getJobPara() {
		return jobPara;
	}

	public void setJobPara(String jobPara) {
		this.jobPara = jobPara;
	}

	public int getJobType() {
		return jobType;
	}

	public void setJobType(int jobType) {
		this.jobType = jobType;
	}

	public int getRunOnStart() {
		return runOnStart;
	}

	public void setRunOnStart(int runOnStart) {
		this.runOnStart = runOnStart;
	}

	public String getDispath() {
		return dispath;
	}

	public void setDispath(String dispath) {
		this.dispath = dispath;
	}

	public String getRepeatRunRule() {
		return repeatRunRule;
	}

	public void setRepeatRunRule(String repeatRunRule) {
		this.repeatRunRule = repeatRunRule;
	}

	public String getErrorDesc() {
		return errorDesc;
	}

	public void setErrorDesc(String errorDesc) {
		this.errorDesc = errorDesc;
	}

	public boolean isJobRun() {
		return isJobRun;
	}

	public void setJobRun(boolean isJobRun) {
		this.isJobRun = isJobRun;
	}

	public String getKey() {
		if(key == null){
			this.key = new StringBuilder(this.getJobGroupName()).append("_").append(this.getJobIdInGroup()).toString();
		}
		return key;
	}

	public int getRetryCount() {
		return retryCount;
	}

	public void setRetryCount(int retryCount) {
		this.retryCount = retryCount;
	}

	@Override
	public void run() {
		if(this.isJobRun){
			return;
		}
		this.isJobRun = true;
		if(this.jobType == JOB_DB){
			
		}else{
			
		}
		
		//执行任务
		Object obj = null;
		try {
			ApplicationContext a = null;
			obj = a.getBean(this.serviceName);
			if(obj==null){
				obj = Thread.currentThread().getContextClassLoader().loadClass(this.serviceName).newInstance();
				Method method = null;
				if(this.jobParams==null || this.jobParams.length ==0){
					method = obj.getClass().getMethod(this.methodName, (Class[])null);
				}else{
					Method[] tmp = obj.getClass().getDeclaredMethods();
					for(int i= 0;i<tmp.length;i++){
						if(tmp[i].getName().equals(this.methodName)){
							Class[] paramTypes = tmp[i].getParameterTypes();
							if(paramTypes.length == this.jobParams.length){
								int num = 0;
								for(int j=0;j<this.jobParams.length;j++){
									if(ClassUtils.isAssignableValue(paramTypes[j], this.jobParams[j])){
										num++;
									}else{
										break;
									}
								}
								if(num == this.jobParams.length){
									method = tmp[i];
									break;
								}
							}
						}
					}
				}
				//可以考虑将这个method的查找缓存起来 Map<String,Method> cache = new ConcurrentHashMap<String,Method>();
				method.invoke(obj, jobParams);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
}
